/**
 * 错误处理中间件
 * 统一处理应用程序中的错误
 */
const errorHandler = async (ctx, next) => {
  try {
    await next();
  } catch (error) {
    // 记录错误日志
    console.error('应用错误:', error);
    
    // 默认错误状态码和消息
    let statusCode = 500;
    let message = '服务器内部错误';
    
    // 根据错误类型设置不同的响应
    if (error.name === 'ValidationError') {
      // Mongoose 验证错误
      statusCode = 400;
      message = '请求数据验证失败';
      
      // 收集所有验证错误消息
      const validationErrors = {};
      for (const field in error.errors) {
        validationErrors[field] = error.errors[field].message;
      }
      
      ctx.status = statusCode;
      ctx.body = {
        success: false,
        message,
        errors: validationErrors
      };
      return;
    }
    
    if (error.name === 'CastError' && error.kind === 'ObjectId') {
      // Mongoose ObjectId 转换错误
      statusCode = 400;
      message = '无效的资源ID';
    }
    
    if (error.code === 11000) {
      // MongoDB 唯一索引冲突
      statusCode = 409;
      message = '资源已存在';
      
      // 尝试提取冲突的字段
      const field = Object.keys(error.keyValue)[0];
      if (field) {
        message = `${field} 已被使用`;
      }
    }
    
    // 自定义错误（带有status和message属性）
    if (error.status && error.message) {
      statusCode = error.status;
      message = error.message;
    }
    
    // 设置响应
    ctx.status = statusCode;
    ctx.body = {
      success: false,
      message,
      // 仅在开发环境返回详细错误信息
      ...(process.env.NODE_ENV === 'development' && {
        error: error.message,
        stack: error.stack
      })
    };
    
    // 触发应用级错误事件
    ctx.app.emit('error', error, ctx);
  }
};

/**
 * 404 处理中间件
 * 处理未找到的路由
 */
const notFoundHandler = async (ctx, next) => {
  await next();
  
  if (ctx.status === 404 && !ctx.body) {
    ctx.status = 404;
    ctx.body = {
      success: false,
      message: '请求的资源未找到'
    };
  }
};

/**
 * 日志中间件
 * 记录请求和响应信息
 */
const loggerMiddleware = async (ctx, next) => {
  const start = Date.now();
  const { method, url, header, ip } = ctx.request;
  
  console.log(`[${new Date().toISOString()}] ${method} ${url} - ${ip}`);
  
  try {
    await next();
    
    const duration = Date.now() - start;
    const { status, body } = ctx.response;
    
    console.log(`[${new Date().toISOString()}] ${method} ${url} - ${status} - ${duration}ms`);
  } catch (error) {
    const duration = Date.now() - start;
    console.error(`[${new Date().toISOString()}] ${method} ${url} - 错误: ${error.message} - ${duration}ms`);
    throw error;
  }
};

module.exports = {
  errorHandler,
  notFoundHandler,
  loggerMiddleware
};